/* 
 * Gneat (http://gneat.org)
 *
 * (C) Copyright 2011 and beyond - Claudio Stella, all rights reserved.
 *
 * This file is part of Gneat.
 *
 * Gneat is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License (LGPL)
 * as published by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Gneat is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * and the GNU General Public License, for completeness, along with Gneat.  
 * If not, see <http://www.gnu.org/licenses/>.
 */
package org.neatshell.gneat.client.event;

import org.neatshell.gneat.client.event.dead.BlurEvent;
import org.neatshell.gneat.client.event.dead.ChangeEvent;
import org.neatshell.gneat.client.event.dead.ErrorEvent;
import org.neatshell.gneat.client.event.dead.Event;
import org.neatshell.gneat.client.event.dead.FocusEvent;
import org.neatshell.gneat.client.event.dead.LoadEvent;
import org.neatshell.gneat.client.event.dead.ScrollEvent;
import org.neatshell.gneat.client.event.dead.SubmitEvent;
import org.neatshell.gneat.client.event.dead.keyboard.KeyDownEvent;
import org.neatshell.gneat.client.event.dead.keyboard.KeyPressEvent;
import org.neatshell.gneat.client.event.dead.keyboard.KeyUpEvent;
import org.neatshell.gneat.client.event.dead.mouse.ClickEvent;
import org.neatshell.gneat.client.event.dead.mouse.DblClickEvent;
import org.neatshell.gneat.client.event.dead.mouse.MouseDownEvent;
import org.neatshell.gneat.client.event.dead.mouse.MouseMoveEvent;
import org.neatshell.gneat.client.event.dead.mouse.MouseOutEvent;
import org.neatshell.gneat.client.event.dead.mouse.MouseOverEvent;
import org.neatshell.gneat.client.event.dead.mouse.MouseUpEvent;
import org.neatshell.gneat.client.event.keyboard.IKeyDownEvent;
import org.neatshell.gneat.client.event.keyboard.IKeyPressEvent;
import org.neatshell.gneat.client.event.keyboard.IKeyUpEvent;
import org.neatshell.gneat.client.event.live.CustomEvent;
import org.neatshell.gneat.client.event.mouse.IClickEvent;
import org.neatshell.gneat.client.event.mouse.IDblClickEvent;
import org.neatshell.gneat.client.event.mouse.IMouseDownEvent;
import org.neatshell.gneat.client.event.mouse.IMouseMoveEvent;
import org.neatshell.gneat.client.event.mouse.IMouseOutEvent;
import org.neatshell.gneat.client.event.mouse.IMouseOverEvent;
import org.neatshell.gneat.client.event.mouse.IMouseUpEvent;
import org.neatshell.gneat.client.handler.BlurHandler;
import org.neatshell.gneat.client.handler.ChangeHandler;
import org.neatshell.gneat.client.handler.CustomHandler;
import org.neatshell.gneat.client.handler.ErrorHandler;
import org.neatshell.gneat.client.handler.FocusHandler;
import org.neatshell.gneat.client.handler.Handler;
import org.neatshell.gneat.client.handler.LoadHandler;
import org.neatshell.gneat.client.handler.ScrollHandler;
import org.neatshell.gneat.client.handler.SubmitHandler;
import org.neatshell.gneat.client.handler.keyboard.KeyDownHandler;
import org.neatshell.gneat.client.handler.keyboard.KeyPressHandler;
import org.neatshell.gneat.client.handler.keyboard.KeyUpHandler;
import org.neatshell.gneat.client.handler.mouse.ClickHandler;
import org.neatshell.gneat.client.handler.mouse.DblClickHandler;
import org.neatshell.gneat.client.handler.mouse.MouseDownHandler;
import org.neatshell.gneat.client.handler.mouse.MouseMoveHandler;
import org.neatshell.gneat.client.handler.mouse.MouseOutHandler;
import org.neatshell.gneat.client.handler.mouse.MouseOverHandler;
import org.neatshell.gneat.client.handler.mouse.MouseUpHandler;

import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.DomEvent;
import com.google.gwt.regexp.shared.RegExp;
import com.google.gwt.user.client.ui.Widget;

public class Events {
	public static final String DOM = 
	"\\b("                                                 +
	"blur|change|error|focus|load|resize|submit|scroll|"         +
	"keydown|keypress|keyup|"                              +
	"click|dblclick|mousedown|mouseup|mouseout|mouseover|mousemove" +
	")\\b";
	
	
//    'mousewheel'
//
//    'touchstart'
//    'touchmove'
//    'touchend'
//    'touchcancel'
//    'gesturestart'
//    'gesturechange'
//    'gestureend'
//
//      "drag":
//      "dragend":
//      "dragenter":
//      "dragleave":
//      "dragover":
//      "dragstart":
//      "drop":

	private static boolean isDOM(String event) {
		return RegExp.compile(DOM).test(event);
	}

	/**
	 * Live Triggering
	 * @param event
	 * @param widget
	 */
	public static void trigger(String event, Widget widget) {
		if (isDOM(event)) {
			if (event.equals(IClickEvent.NAME)) {
				DomEvent.fireNativeEvent(Document.get().createClickEvent(0, 0, 0, 0, 0, false, false, false, false), widget);
			}
			else if (event.equals(IMouseUpEvent.NAME)) {
				DomEvent.fireNativeEvent(Document.get().createMouseUpEvent(0, 0, 0, 0, 0, false, false, false, false, NativeEvent.BUTTON_LEFT), widget);
			}
			else if (event.equals(IMouseDownEvent.NAME)) {
				DomEvent.fireNativeEvent(Document.get().createMouseDownEvent(0, 0, 0, 0, 0, false, false, false, false, NativeEvent.BUTTON_LEFT), widget);
			}
			else if (event.equals(IMouseOutEvent.NAME)) {
				DomEvent.fireNativeEvent(Document.get().createMouseOutEvent(0, 0, 0, 0, 0, false, false, false, false, 0, null), widget);
			}
			else if (event.equals(IMouseOverEvent.NAME)) {
				DomEvent.fireNativeEvent(Document.get().createMouseOverEvent(0, 0, 0, 0, 0, false, false, false, false, 0, null), widget);
			}
			else if (event.equals(IMouseMoveEvent.NAME)) {
				DomEvent.fireNativeEvent(Document.get().createMouseMoveEvent(0, 0, 0, 0, 0, false, false, false, false, NativeEvent.BUTTON_LEFT), widget);
			}
			else if (event.equals(IDblClickEvent.NAME)) {
				DomEvent.fireNativeEvent(Document.get().createDblClickEvent(0, 0, 0, 0, 0, false, false, false, false), widget);
			}
			else if (event.equals(IKeyDownEvent.NAME)) {
				DomEvent.fireNativeEvent(Document.get().createKeyDownEvent(false, false, false, false, 0), widget);
			}
			else if (event.equals(IKeyPressEvent.NAME)) {
				DomEvent.fireNativeEvent(Document.get().createKeyPressEvent(false, false, false, false, 0), widget);
			}
			else if (event.equals(IKeyUpEvent.NAME)) {
				DomEvent.fireNativeEvent(Document.get().createKeyUpEvent(false, false, false, false, 0), widget);
			}
			else {
				DomEvent.fireNativeEvent(Document.get().createHtmlEvent(event, true, true), widget);
			}
		}
		else {
			widget.fireEvent(new CustomEvent(event));
		}
	}
	
	/**
	 * Dead Triggering
	 * @param event
	 * @param handler
	 */
	public static void trigger(String event, Handler handler) {
		Event<?> e = null;
		if (isDOM(event)) {
			if (event.equals(IKeyPressEvent.NAME)) {
				e = new KeyPressEvent();
				((KeyPressHandler) handler).onKeyPress((KeyPressEvent) e, handler.current());
			}
			else if (event.equals(IKeyDownEvent.NAME)) {
				e = new KeyDownEvent();
				((KeyDownHandler) handler).onKeyDown((KeyDownEvent) e, handler.current());
			}
			else if (event.equals(IKeyUpEvent.NAME)) {
				e = new KeyUpEvent();
				((KeyUpHandler) handler).onKeyUp((KeyUpEvent) e, handler.current());
			}
			else if (event.equals(IClickEvent.NAME)) {
				e = new ClickEvent();
				((ClickHandler) handler).onClick((ClickEvent) e, handler.current());
			}
			else if (event.equals(IDblClickEvent.NAME)) {
				e = new DblClickEvent();
				((DblClickHandler) handler).onDblClick((DblClickEvent) e, handler.current());
			}
			else if (event.equals(IMouseMoveEvent.NAME)) {
				e = new MouseMoveEvent();
				((MouseMoveHandler) handler).onMouseMove((MouseMoveEvent) e, handler.current());
			}
			else if (event.equals(IMouseOverEvent.NAME)) {
				e = new MouseOverEvent();
				((MouseOverHandler) handler).onMouseOver((MouseOverEvent) e, handler.current());
			}
			else if (event.equals(IMouseOutEvent.NAME)) {
				e = new MouseOutEvent();
				((MouseOutHandler) handler).onMouseOut((MouseOutEvent) e, handler.current());
			}
			else if (event.equals(IMouseDownEvent.NAME)) {
				e = new MouseDownEvent();
				((MouseDownHandler) handler).onMouseDown((MouseDownEvent) e, handler.current());
			}
			else if (event.equals(IMouseUpEvent.NAME)) {
				e = new MouseUpEvent();
				((MouseUpHandler) handler).onMouseUp((MouseUpEvent) e, handler.current());
			}			
			else if (event.equals(IBlurEvent.NAME)) {
				e = new BlurEvent();
				((BlurHandler) handler).onBlur((BlurEvent) e, handler.current());
			}
			else if (event.equals(IChangeEvent.NAME)) {
				e = new ChangeEvent();
				((ChangeHandler) handler).onChange((ChangeEvent) e, handler.current());
			}
			else if (event.equals(IErrorEvent.NAME)) {
				e = new ErrorEvent();
				((ErrorHandler) handler).onError((ErrorEvent) e, handler.current());
			}
			else if (event.equals(IFocusEvent.NAME)) {
				e = new FocusEvent();
				((FocusHandler) handler).onFocus((FocusEvent) e, handler.current());
			}
			else if (event.equals(ILoadEvent.NAME)) {
				e = new LoadEvent();
				((LoadHandler) handler).onLoad((LoadEvent) e, handler.current());
			}
			else if (event.equals(IScrollEvent.NAME)) {
				e = new ScrollEvent();
				((ScrollHandler) handler).onScroll((ScrollEvent) e, handler.current());
			}			
			else if (event.equals(ISubmitEvent.NAME)) {
				e = new SubmitEvent();
				((SubmitHandler) handler).onSubmit((SubmitEvent) e, handler.current());
			}
		}
		else ((CustomHandler) handler).onEvent(new CustomEvent(event), handler.current());

		if (e != null && e.bubble()) handler.current().parent().trigger(event);
	}
}